/**
 * HSI-88.h
 *
 * HSI-88 Fast S88 PC Interface 
 * 
 * This software emulates the HSI-88 from Littfinski. It has three S88 busses that it activly scans only reporting the changed
 * signals to the PC.
 *
 * Author:   Elze Kool <efrkool@live.nl>
 * Date:     27-nov-2009
 * Software: AVR-GCC
 * Target:   AT90USB162 @ 8Mhz on the Olimex AVR-USB-162 development board
 *
 * Based on the LUFA USB Library and Serial CDC Example:
 * Parts Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com)
 *
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <util/atomic.h>
#include "RingBuff.h"

/**
 * Initialize RingBuffer
 * @param RingBuffer_t Buffer Pointer to ringbuffer
 * @param uint32_t Size of buffer
 **/
void RingBuffer_Initialize(RingBuffer_t* Buffer, uint32_t Size)
{
	// Prevent ISR's to interrupt
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
	{
		// Allocate memory for ringbuffer
		Buffer->Storage = (RingBuffer_Data_t*) malloc(Size * sizeof(RingBuffer_Data_t));
		Buffer->Size = Size;
		
		// Reset Load, Read Position 
		Buffer->LoadPosition = 0;
		Buffer->ReadPosition = 0;
		Buffer->Count = 0;
	}
}

/**
 * Reset buffer to initial state
 * @param RingBuffer_t Buffer Pointer to ringbuffer 
 **/
void RingBuffer_Reset(RingBuffer_t* Buffer)
{
	// Prevent ISR's to interrupt
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
	{
		// Reset Load, Read Position 
		Buffer->LoadPosition = 0;
		Buffer->ReadPosition = 0;
		Buffer->Count = 0;
	}
}


/**
 * Reset buffer to initial state
 * @param RingBuffer_t Buffer Pointer to ringbuffer 
 * @param RingBuffer_Data_t Element Element to add
 **/
void RingBuffer_AddElement(RingBuffer_t* Buffer, RingBuffer_Data_t Element)
{
	// Prevent ISR's to interrupt
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
	{
		// Exit when buffer full
		if (Buffer->Count == Buffer->Size) return;
		
		// Add data to storage
		Buffer->Storage[Buffer->LoadPosition] = Element;
		Buffer->LoadPosition = (Buffer->LoadPosition + 1) % (Buffer->Size);
		
		// Increase number of element
		Buffer->Count = Buffer->Count + 1;
	}
}

/**
 * Reset buffer to initial state
 * @param RingBuffer_t Buffer Pointer to ringbuffer 
 * @return RingBuffer_Data_t Element Element read
 **/
RingBuffer_Data_t RingBuffer_GetElement(RingBuffer_t* Buffer)
{
	// Storage for Element
	RingBuffer_Data_t Element;
	
	// Prevent ISR's to interrupt
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
	{
		// If no elements in buffer return 0
		if (Buffer->Count == 0) return 0;

		// Read element from storage
		Element = Buffer->Storage[Buffer->ReadPosition];
		Buffer->ReadPosition = (Buffer->ReadPosition + 1) % (Buffer->Size);
		
		// Decrease number of element
		Buffer->Count = Buffer->Count - 1;
	}
	
	// Return element
	return Element;	
}
